package wh.对称二叉树;

import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;

/**
 * @author: wh(1835734390 @ qq.com)
 * @date: 2022/4/2 18:37
 * @description:给你一个二叉树的根节点 root ， 检查它是否轴对称
 * @version:
 */
public class Solution {
    public static void main(String[] args) {
        TreeNode root = new TreeNode(1,new TreeNode(2),new TreeNode(2));
        boolean symmetric = isSymmetric3(root);
        System.out.println(symmetric);
    }

    //解法1 错误！！！ 只凭中序遍历的结果不可以确定一棵树的形状!!!
    public static boolean isSymmetric(TreeNode root) {
        //新建一个集合，存储中序遍历的结果
        List<Integer> res = new ArrayList<>();
        //新建一个栈
        Deque<TreeNode> stk = new LinkedList<>();
        while (root != null || !stk.isEmpty()) {
            while (root != null) {
                //入栈
                stk.push(root);
                root = root.left;
            }
            //出栈，而且把出栈的节点值放入集合中
            root = stk.pop();
            res.add(root.val);
            root = root.right;
        }
        //将list转为数组
        Object[] array = res.toArray();
        int i = 0;
        int j = array.length - 1;
        if (j % 2 != 0){
            return false;
        }
        //首尾比较
        while (i != j){
            if(array[i] == array[j]){
                ++i;
                --j;
            }else {
                return false;
            }
        }
        return true;
    }


    //解法2 递归实现(深度优先遍历）
    public static boolean isSymmetric2(TreeNode root) {
        if(root == null){
            return true;
        }
        return dfs(root.left,root.right);
    }
    static boolean dfs(TreeNode left, TreeNode right) {
        //递归的终止条件是两个节点都为空 递归实现一定要考虑到终止条件，防止发生死循环
        //或者两个节点中有一个为空
        //或者两个节点的值不相等
        if(left==null && right==null) {
            return true;
        }
        if(left==null || right==null) {
            return false;
        }
        if(left.val!=right.val) {
            return false;
        }
        //再递归的比较 左节点的左孩子 和 右节点的右孩子
        //以及比较  左节点的右孩子 和 右节点的左孩子
        return dfs(left.left,right.right) && dfs(left.right,right.left);
    }

    //解法3队列实现,广度优先遍历
    public static boolean isSymmetric3(TreeNode root) {
        if(root==null || (root.left==null && root.right==null)) {
            return true;
        }
        //用队列保存节点 这里使用有序的linkedlist集合来模拟队列
        //父类只能调用子类重写的方法，无法调用子类自己的方法
        LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
        //将根节点的左右孩子放到队列中
        queue.add(root.left);
        queue.add(root.right);
        while(queue.size()>0) {
            //从队列中取出两个节点，再比较这两个节点
            TreeNode left = queue.removeFirst();
            TreeNode right = queue.removeFirst();
            //如果两个节点都为空就终止这一次循环，开启下一次循环。两者有一个为空就返回false
            if(left==null && right==null) {
                continue;
            }
            if(left==null || right==null) {
                return false;
            }
            if(left.val!=right.val) {
                return false;
            }
            //将左节点的左孩子， 右节点的右孩子放入队列
            queue.add(left.left);
            queue.add(right.right);
            //将左节点的右孩子，右节点的左孩子放入队列
            queue.add(left.right);
            queue.add(right.left);
        }

        return true;
    }

}
